#include "iConfig.hpp"
#include <glf/config/platform.h>

#if GLF_ENABLE_DEBUGGER

#include <glf/debugger/fileSystem.h>

#if defined(GLF_PLATFORM_CTR)
#   include <nn/os.h>
#elif defined(GLF_PLATFORM_PSP2)
#   include <kernel/iofilemgr.h>
#else
#   include <sys/types.h>
#   include <sys/stat.h>
#   include <time.h>
#endif

#if defined(GLF_PLATFORM_WIN32) || defined(GLF_PLATFORM_WP8)
#	include <direct.h>
#endif

namespace glf
{
namespace debugger
{
	int createFolder(const char* path)
	{
#if defined(GLF_PLATFORM_WIN32) || defined(GLF_PLATFORM_WP8)
		return _mkdir(path);
#elif defined(GLF_PLATFORM_CTR)
		return -1;
#elif defined(GLF_PLATFORM_PSP2)
		return sceIoMkdir(path, SCE_STM_RWU) == 0;
#else
		return mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#endif
	}

	FileSystem::FileSystem() :
		Module("FILESYS")
	{
		
	}

	FileSystem::~FileSystem()
	{

	}

	void FileSystem::UpdateFrame()
	{
		
	}

	void FileSystem::Parse(int type, PacketReader& in)
	{
		switch(type)
		{
			case MESSAGE_REQUEST_SYSTEM_TIME:
			{
#if defined(GLF_PLATFORM_CTR)
				nn::os::Tick rawtime;
#else
				time_t rawtime;
				time(&rawtime);				

#if GLF_PLATFORM_WP8
				tm time;
				gmtime_s(&time, &rawtime);
#else
				gmtime(&rawtime);
#endif
#endif
				PacketWriter& pw = GetPacketWriter();
				pw.Init(MESSAGE_SYSTEM_TIME);
				pw.Write((uint64)rawtime);
				Send(pw);
				break;
			}

//			case MESSAGE_REQUEST_FILE_ENTRIES:
//			{
//				mPacketWriter.init(MESSAGE_FILE_ENTRIES);
//				mPacketWriter.write(FileSystemPCResourceFolder.c_str());
//				sendFileEntries(FileSystemSaveFolder);
//				mPacketWriter.flush(mNetSocket);
//				break;
//			}
//
//			case MESSAGE_FILE_CONTENT:
//			{
//				stringdbg file = FileSystemSaveFolder;
//				file += in.readString();
//				bool folder = in.readIntLE() != 0;
//				uint size = in.readIntLE();
//				uint compressedSize = in.readIntLE();
//
//				if(folder)
//				{
//					printf("creating folder %s\n", file.c_str());
//					GLITCH_DEBUG_ONLY(s32 ret =) createFolder(file.c_str());
//					GLF_ASSERT(ret == 0);
//				}
//				else
//				{
//					printf("writing file %s\n", file.c_str());
//
//					// uncompressing file
//					uchar* buffer = new uchar[size];
//					unsigned long destLen = (unsigned long)size;
//					s32 ret = Z_OK;
//					if(size > 0)
//					{
//						ret = uncompress(buffer, &destLen, in.getData(), compressedSize);
//					}
//					GLF_ASSERT(ret == Z_OK);
//					GLF_ASSERT(destLen == size);
//					//const uchar* buffer = in.getData();
//
//					if(ret == Z_OK && destLen == size)
//					{
//						// writing
//						FILE* f = fopen(file.c_str(), "wb+");
//						GLF_ASSERT(f != NULL);
//						if(f != NULL)
//						{
//							fwrite(buffer, size, 1, f);
//							fclose(f);
//							printf("done\n");
//						}
//					}
//					else
//					{
//						printf("error: ret=%d destLen=%lu size=%u\n", ret, destLen, size);
//					}
//					delete[] buffer;
//				}
//				break;
//			}
//
//			case MESSAGE_RESOURCES_SYNCHRONIZED:
//			{
//				ResourceSynchronizationState = E_DRSST_DONE;
//				break;
//			}
//
//			case MESSAGE_REMOVE_FILE:
//			{
//#if !defined(GLITCH_3DS_PLATFORM)
//				stringdbg file = FileSystemSaveFolder;
//				file += in.readString();
//
//				struct stat fileStat;
//				stat(file.c_str(), &fileStat);
//
//				printf("Removing %s\n", file.c_str());
//				s32 ret = remove(file.c_str());
//
//				if(ret != 0)
//				{
//#ifdef WIN32
//					ret = _rmdir(file.c_str());
//#else
//					ret = rmdir(file.c_str());
//#endif
//				}
//				if(ret != 0)
//					printf("Failed\n");
//#endif
//				break;
//			}
//
//			case MESSAGE_COPY_ALL_RESOURCES:
//			{
//				copyResourcesToSaveFolder();
//				break;
//			}
//
//			case MESSAGE_REQUEST_SYNCHRONIZE_RESOURCES:
//			{
//				if(ResourceSynchronizationState == E_DRSST_DONE && FileSystemSaveFolder.length() > 0)
//				{
//					ResourceSynchronizationState = E_DRSST_SYNCHRONIZE_REQUEST;
//				}
//				break;
//			}
		}
	}

//	void FileSystem::SendFileEntries(const stringdbg& folder)
//	{
//#if !defined(GLITCH_3DS_PLATFORM)
//		ScopeMutex mutex;
//		char oldFolder[256];
//		strcpy(oldFolder, Device->getFileSystem()->getWorkingDirectory());
//		bool ret = Device->getFileSystem()->changeWorkingDirectoryTo(folder.c_str());
//		GLF_ASSERT(ret);
//
//		io::IFileListPtr list = Device->getFileSystem()->createFileList();
//
//		uint count = 0;
//		for(uint i = 0; i < list->getFileCount(); i++)
//		{
//			if(list->isDirectory(i))
//			{
//				if(strcmp(list->getFileName(i), "..") == 0 || strcmp(list->getFileName(i), ".") == 0)
//					continue;
//			}
//			count++;
//		}
//		mPacketWriter.write(count);
//
//		for(uint i = 0; i < list->getFileCount(); i++)
//		{
//			if(list->isDirectory(i))
//			{
//				if(strcmp(list->getFileName(i), "..") == 0 || strcmp(list->getFileName(i), ".") == 0)
//					continue;
//			}
//
//			mPacketWriter.write(list->getFileName(i));
//			mPacketWriter.write(list->isDirectory(i));
//
//			if(list->isDirectory(i))
//			{
//				stringdbg path = folder;
//				path += "/";
//				path += list->getFileName(i);
//				sendFileEntries(path);
//			}
//			else
//			{
//				struct stat fileStat;
//				stat(list->getFileName(i), &fileStat);
//				time_t rawtime = fileStat.st_mtime;
//				mPacketWriter.write((u64)rawtime);
//				mPacketWriter.write((uint)fileStat.st_size);
//			}
//		}
//
//		ret = Device->getFileSystem()->changeWorkingDirectoryTo(oldFolder);
//		GLF_ASSERT(ret);
//#endif
//	}

//#ifdef GLITCH_USE_IPHONEOS_DEVICE
//	extern "C" void glitchGetSaveFolder(char* buffer, int bufferSize);
//	extern "C" bool glitchShowSynchronizationPopup();
//	extern "C" bool glitchIsIgnoringInteractionEvents();
//	extern "C" void glitchSetIgnoringInteractionEvents(bool ignoring);
//#endif

//	void FileSystem::InitResourceSynchronization(bool showPopup)
//	{
//		if(strlen(GLITCH_DEBUGGER_PC_SYNCHRONIZATION_FOLDER) == 0)
//			return;
//
//#ifdef GLITCH_USE_IPHONEOS_DEVICE
//		char saveFolder[512];
//		glitchGetSaveFolder(saveFolder, sizeof(saveFolder));
//		setSynchronizationFolders(GLITCH_DEBUGGER_PC_SYNCHRONIZATION_FOLDER, Device->getFileSystem()->getWorkingDirectory(), saveFolder);
//
//		if(showPopup && glitchShowSynchronizationPopup())
//		{
//			bool wasIgnoring = glitchIsIgnoringInteractionEvents();
//			if(!wasIgnoring)
//				glitchSetIgnoringInteractionEvents(true);
//
//			synchronizeFiles(60 * 5);
//
//			if(!wasIgnoring)
//				glitchSetIgnoringInteractionEvents(false);
//		}
//#endif
//	}
//
//	void formatSlashes(stringdbg& path)
//	{
//		// change backslashes to slashes
//		for(uint i = 0; i < path.length(); i++)
//		{
//			if(path[i] == '\\')
//				path[i] = '/';
//		}
//	}

	//void FileSystem::SetSynchronizationFolders(const char* pcResourceFolder, const char* deviceResourceFolder, const char* deviceSaveFolder)
	//{
	//	FileSystemPCResourceFolder = pcResourceFolder;
	//	FileSystemPCResourceFolder += "/";
	//	FileSystemPCResourceFolder += GLITCH_DEBUGGER_RESOURCE_SUBFOLDER;
	//	formatSlashes(FileSystemPCResourceFolder);

	//	FileSystemDeviceResourceFolder = deviceResourceFolder;
	//	FileSystemDeviceResourceFolder += "/";
	//	FileSystemDeviceResourceFolder += GLITCH_DEBUGGER_RESOURCE_SUBFOLDER;
	//	formatSlashes(FileSystemDeviceResourceFolder);

	//	FileSystemSaveFolder = deviceSaveFolder;
	//	FileSystemSaveFolder += "/";
	//	FileSystemSaveFolder += GLITCH_DEBUGGER_RESOURCE_SUBFOLDER;
	//	formatSlashes(FileSystemSaveFolder);

	//	printf("FileSystemPCResourceFolder %s...\n", FileSystemPCResourceFolder.c_str());
	//	printf("FileSystemDeviceResourceFolder %s...\n", FileSystemDeviceResourceFolder.c_str());
	//	printf("FileSystemSaveFolder %s...\n", FileSystemSaveFolder.c_str());

	//	char oldFolder[256];
	//	strcpy(oldFolder, Device->getFileSystem()->getWorkingDirectory());
	//	
	//	const char* path = FileSystemSaveFolder.c_str();

	//	// construct path if not exists
	//	char* slash = (char*)strchr(path, '/');
	//	while(slash != NULL)
	//	{
	//		*slash = 0;
	//		if(!Device->getFileSystem()->changeWorkingDirectoryTo(path))
	//		{
	//			GLITCH_DEBUG_ONLY(s32 ret =) createFolder(path);
	//			GLF_ASSERT(ret == 0);
	//		}
	//		*slash = '/';
	//		slash = (char*)strchr(slash + 1, '/');
	//	}
	//	if(!Device->getFileSystem()->changeWorkingDirectoryTo(path))
	//	{
	//		GLITCH_DEBUG_ONLY(s32 ret =) createFolder(path);
	//		GLF_ASSERT(ret == 0);
	//	}

	//	GLITCH_DEBUG_ONLY(bool ret =) Device->getFileSystem()->changeWorkingDirectoryTo(oldFolder);
	//	GLF_ASSERT(ret);
	//}

	//bool FileSystem::GetSynchronizedFileName(const char* fileName, char* outFileName, uint outBufferSize)
	//{
	//	//printf("getSynchronizedFileName %s...\n", fileName);

	//	if(FileSystemSaveFolder.length() == 0 || FileSystemDeviceResourceFolder.length() == 0)
	//		return false;

	//	stringdbg temp = fileName;
	//	formatSlashes(temp);
	//	const char* path = temp.c_str();
	//	
	//	// path already converted to save folder?
	//	if(strstr(path, FileSystemSaveFolder.c_str()) != NULL)
	//		return false;

	//	// absolute resource path? if so, skip the absolute path
	//	if(strstr(path, FileSystemDeviceResourceFolder.c_str()) == path)
	//		path += FileSystemDeviceResourceFolder.length();
	//	
	//	strcpy(outFileName, FileSystemSaveFolder.c_str());
	//	
	//	// truncate subfolder part
	//	outFileName[FileSystemSaveFolder.length() - strlen(GLITCH_DEBUGGER_RESOURCE_SUBFOLDER) - 1] = '\0';

	//	// append filename
	//	sprintf(outFileName + strlen(outFileName), "/%s", path);
	//	GLF_ASSERT(strlen(outFileName) < outBufferSize);
	//	//printf("mapping to %s\n", outFileName);
	//	return true;
	//}

	//bool FileSystem::SynchronizeFiles(uint timeOutSeconds)
	//{
	//	ResourceSynchronizationState = E_DRSST_SYNCHRONIZING;

	//	if(!waitForConnection(timeOutSeconds))
	//	{
	//		ResourceSynchronizationState = E_DRSST_DONE;
	//		return false;
	//	}

	//	mPacketWriter.init(MESSAGE_START_SYNCHRONIZE_RESOURCES);
	//	mPacketWriter.flush(mNetSocket);

	//	while(ResourceSynchronizationState == E_DRSST_SYNCHRONIZING)
	//	{
	//		if(!IsConnected())
	//		{
	//			if(!waitForConnection(timeOutSeconds))
	//			{
	//				ResourceSynchronizationState = E_DRSST_DONE;
	//				return false;
	//			}

	//			mPacketWriter.init(MESSAGE_START_SYNCHRONIZE_RESOURCES);
	//			mPacketWriter.flush(mNetSocket);
	//		}

	//		update();

	//		if(Device != NULL)
	//			Device->sleep(5);
	//	}
	//	return true;
	//}

	//void FileSystem::CopyResourcesToSaveFolder()
	//{
	//	if(FileSystemSaveFolder.length() > 0 && FileSystemSaveFolder.length() > 0)
	//	{
	//		copyFiles(FileSystemDeviceResourceFolder, FileSystemSaveFolder);
	//		printf("Synchronization done\n");
	//	}
	//	else
	//	{
	//		printf("Synchronization paths not defined\n");
	//	}
	//}

	//void FileSystem::CopyFiles(const stringdbg& srcFolder, const stringdbg& destFolder)
	//{
	//	printf("copyFiles: %s to %s\n", srcFolder.c_str(), destFolder.c_str());

	//	char oldFolder[256];
	//	strcpy(oldFolder, Device->getFileSystem()->getWorkingDirectory());

	//	if(!Device->getFileSystem()->changeWorkingDirectoryTo(destFolder.c_str()))
	//	{
	//		s32 ret = createFolder(destFolder.c_str());
	//		if(ret != 0)
	//		{
	//			printf("error creating folder %s\n", destFolder.c_str());
	//		}
	//	}

	//	bool ret = Device->getFileSystem()->changeWorkingDirectoryTo(srcFolder.c_str());
	//	GLF_ASSERT(ret);
	//	if(!ret)
	//	{
	//		printf("can't change folder to %s\n", srcFolder.c_str());
	//	}

	//	io::IFileListPtr list = Device->getFileSystem()->createFileList();

	//	for(uint i = 0; i < list->getFileCount(); i++)
	//	{
	//		if(list->isDirectory(i))
	//		{
	//			if(strcmp(list->getFileName(i), "..") == 0 || strcmp(list->getFileName(i), ".") == 0)
	//				continue;
	//		}

	//		stringdbg srcPath = srcFolder;
	//		srcPath += "/";
	//		srcPath += list->getFileName(i);
	//		
	//		stringdbg dstPath = destFolder;
	//		dstPath += "/";
	//		dstPath += list->getFileName(i);

	//		if(list->isDirectory(i))
	//		{
	//			copyFiles(srcPath, dstPath);
	//		}
	//		else
	//		{
	//			printf("copyFile: %s\n", list->getFileName(i));
	//			char buffer[4096];
	//			FILE* src = fopen(srcPath.c_str(), "rb");
	//			if(src != NULL)
	//			{
	//				FILE* dst = fopen(dstPath.c_str(), "wb+");
	//				if(dst != NULL)
	//				{
	//					s32 count = 0;
	//					while(true)
	//					{
	//						count = fread(buffer, 1, sizeof(buffer), src);
	//						
	//						if(count <= 0)
	//							break;

	//						fwrite(buffer, 1, count, dst);
	//					}
	//					fclose(dst);
	//				}
	//				else
	//				{
	//					printf("error writing %s\n", dstPath.c_str());
	//				}
	//				fclose(src);
	//			}
	//			else
	//			{
	//				printf("error reading %s\n", srcPath.c_str());
	//			}
	//		}
	//	}

	//	GLITCH_DEBUG_ONLY(ret =) Device->getFileSystem()->changeWorkingDirectoryTo(oldFolder);
	//	GLF_ASSERT(ret);
	//}

} //namespace debugger
} //namespace glf

#endif // GLF_ENABLE_DEBUGGER
